

import os
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import sip
import sys

sys.path.append(os.path.dirname(__file__))
import makeui

context = None

ui_page_editors = []

def init(context_):
    global context
    context = context_

def toUiJson(node, config):
    global context
    # class
    p_class = node.get_prop('class')
    config['widget'] = p_class
    config['id'] = node.get_id()

    # properties
    config['properties'] = {}
    config['pos'] = {}
    config['data'] = {}
    props = node.get_props()

    properties = makeui.get_properties(p_class)

    data_service = context.find_service("DataService")
    project_file = data_service.project_file()

    project_path = os.path.abspath(project_file + "/../")

    for prop in props:
        v_prop = props[prop]
        if type(v_prop) == type('') and v_prop.find('%PROJECT%') >= 0 and project_file != None:
            v_prop = v_prop.replace('%PROJECT%', project_file)
        if type(v_prop) == type('') and v_prop.find('%PROJECTPATH%') >= 0 and project_path != None:
            v_prop = v_prop.replace('%PROJECTPATH%', project_path)
        if prop in properties:
            config['properties'][prop] = v_prop
        elif prop[0:5] == 'POS::':
            config['pos'][prop] = v_prop
        elif prop[0:6] == 'Data::':
            config['data'][prop] = v_prop

    # children
    config['children'] = []
    children = node.get_children()
    for child in children:
        child_config = {}
        toUiJson(child, child_config)
        config['children'].append(child_config)   

class DemoWidget(QWidget):
    def __init__(self, parent):
        super().__init__(parent)

        self.cur_node = None
        self.cur_node_stylesheep = ""
        self.node2widget = {}
        self.layout = None
        self.widget = None
        self.update_node = None

        global ui_page_editors
        ui_page_editors.append(self)

        self.windowTitleChanged.connect(self.onWindowTitleChanged)

    def __del__(self):
        pass
    def onWindowTitleChanged(self, title):
        self.on_init(self.update_node)

    def on_init(self, node):
        self._node = node

        # 生成描述对象
        ui = {}

        children = self._node.get_children()
        for child in children:
            toUiJson(child, ui)
        print(ui)
        
        try:
            if self.layout == None:
                self.node2widget = {}
                self.widget = makeui.makeui(ui, self.node2widget)
                if self.widget == None:
                    return 

                #self.widget.setStyleSheet('#'+self.widget.objectName()+' { background-color: darkgray;border: 1px solid black; }')
                self.layout = QVBoxLayout(self)
                self.layout.addWidget(self.widget)

                #self.layout.setAlignment(Qt.AlignCenter)
                self.layout.setContentsMargins(20, 20, 20, 20)

                self.setLayout(self.layout)
                self.cur_node = None            
            else:
                print("remove old widget ....")
                #if self.cur_node != None and self.cur_node.get_id() in self.node2widget:
                #    wideget = self.node2widget[self.cur_node.get_id()]
                #    wideget.setStyleSheet(self.cur_node_stylesheep)
                self.node2widget = {}

                self.layout.removeWidget(self.widget)
                if self.widget:
                    sip.delete(self.widget)
                self.widget = None
                
                self.widget = makeui.makeui(ui, self.node2widget)
                self.layout.addWidget(self.widget)
                #self.cur_node = None
                
                if self.cur_node != None and self.cur_node.get_id() in self.node2widget:
                    wideget = self.node2widget[self.cur_node.get_id()]
                    self.cur_node_stylesheep = wideget.styleSheet()
                    wideget.setStyleSheet('background-color: rgb(199, 184, 180);')
                    #wideget.setStyleSheet('border-style: outset; border-width:0px; border-color : blue;')
                    #wideget.setStyleSheet('background-color: blue;')
                    #wideget.setStyleSheet(self.cur_node_stylesheep)
        except:
            print("Error! while rendering ui, some error occur!")
        
        return ""
    def on_save(self):
        return ""
    def on_close(self):
        global ui_page_editors
        ui_page_editors.remove(self)
        return ""
    def activate(self, node):
        if self.cur_node != None and self.cur_node.get_id() in self.node2widget:
            wideget = self.node2widget[self.cur_node.get_id()]
            wideget.setStyleSheet(self.cur_node_stylesheep)
        
        if node.get_id() in self.node2widget and type(self.node2widget[node.get_id()]) != type(""):
            wideget = self.node2widget[node.get_id()]
            self.cur_node_stylesheep = wideget.styleSheet()
            wideget.setStyleSheet('background-color: rgb(199, 184, 180);')
            self.cur_node = node
    
    def resizeEvent(self, event):
        size = event.size()

class EditorExtension:
    def data_kind(self):
        return ['Page']
    def is_match_data(self, node):
        if node.get_kind() == 'Page':
            return True
        else:
            return False
    def create_editor(self, parent):
        return DemoWidget(parent)


g_select_node = None

class ActionUpdateResourceNode: 
    def __init__(self, node):
        self.node_ = node

    def on_update_resource(self, value):
        # 获取文件列表
        global context
        data_service = context.find_service("DataService")
        project_path = data_service.project_file()
        
        # resource 
        str_resource_path = os.path.abspath(project_path + "/../resource/")

        print("resource:",str_resource_path)

        # 获取所有resouce
        nodes_list = self.node_.get_children_by_kind('Resource')
        for resource in nodes_list:
            resource.delete()

        for root,dirs,files in os.walk(str_resource_path):
            for file in files:
                file_path1 = os.path.join(root,file)
                file_path = file_path1[len(str_resource_path):]
                new_node = data_service.create_node("Resource", file_path)
                new_node.set_prop('url', file_path)
                self.node_.add_child(new_node)


class ActionMoveNode:
    def __init__(self, node):
        self.node_ = node

    def on_choose_move_item(self, value):
        global g_select_node
        g_select_node = self.node_
    
    def on_move_in(self, value):
        global g_select_node

        if len(self.node_) != 1:
            return 

        for node in g_select_node:
            parent = node.parent()
            parent.remove_child(node)

            if parent.get_prop('class') != self.node_[0].get_prop('class'):
                if self.node_[0].get_prop('class') == 'QGridLayout':
                    node.set_prop('POS::row', '0')
                    node.set_prop('POS::col', '0')
                    node.set_prop('POS::rowspan', '1')
                    node.set_prop('POS::colspan', '1')
                elif self.node_[0].get_prop('class') in ['QTableView', 'QTreeView', 'QListView', 'QHeaderView', 'QUndoView', 'QColumnView']:
                    node.set_prop('POS::row', '0')
                    node.set_prop('POS::col', '0')
                elif self.node_[0].get_prop('class') == 'QTabWidget':
                    node.set_prop('POS::TabName', 'tab')

            self.node_[0].add_child(node)
    
    def on_move_before(self, value):
        global g_select_node

        if len(self.node_) != 1:
            return 

        for node in g_select_node:
            parent = node.parent()
            parent_to = self.node_[0].parent()
            parent.remove_child(node)

            if parent.get_prop('class') != parent_to.get_prop('class'):
                if parent_to.get_prop('class') == 'QGridLayout':
                    node.set_prop('POS::row', '0')
                    node.set_prop('POS::col', '0')
                    node.set_prop('POS::rowspan', '1')
                    node.set_prop('POS::colspan', '1')
                elif parent_to.get_prop('class') in ['QTableView', 'QTreeView', 'QListView', 'QHeaderView', 'QUndoView', 'QColumnView']:
                    node.set_prop('POS::row', '0')
                    node.set_prop('POS::col', '0')
                elif parent_to.get_prop('class') == 'QTabWidget':
                    node.set_prop('POS::TabName', 'tab')

            parent_to.insert_child(node, self.node_[0])


class DataExploreMenu:
    def __init__(self):
        self.menus = []
    def priorty(self):
        return 1000
    def add_menu(self, menu, nodes):
        self.menus = []
    
        if len(nodes) == 0:
            return 

        kinds = [node.get_kind() for node in nodes]

        page_num = 0
        widget_num = 0
        for kind in kinds:
            if kind == 'page':
                page_num = page_num + 1
            elif kind == 'Widget':
                widget_num = widget_num + 1
            else:
                return 
        
        if page_num == 0:
            action = menu.addAction("选择移动对象")
            obj = ActionMoveNode(nodes)
            self.menus.append(obj)
            action.triggered.connect(obj.on_choose_move_item)

        global g_select_node
        if g_select_node != None and page_num == 0 and len(nodes) == 1:
            action = menu.addAction("移动到当前节点前")
            obj = ActionMoveNode(nodes)
            self.menus.append(obj)
            action.triggered.connect(obj.on_move_before)

            action = menu.addAction("移动到当前节点内")
            obj = ActionMoveNode(nodes)
            self.menus.append(obj)
            action.triggered.connect(obj.on_move_in)

class DataExploreUpdateResourceMenu:
    def __init__(self):
        self.menus = []
    def priorty(self):
        return 1000
    def add_menu(self, menu, nodes):
        self.menus = []
    
        if len(nodes) != 1:
            return 

        kind = nodes[0].get_kind()
        if kind != "ResourceGroup":
            return 

        action = menu.addAction("同步资源")
        obj = ActionUpdateResourceNode(nodes[0])
        self.menus.append(obj)
        action.triggered.connect(obj.on_update_resource)

# 建立一个延迟的消息响应
# 修改发生，延时200ms处理
#   针对不同Page,记录消息次数
g_update_times = {}

class MyEvent:
    pass

from threading import Timer
def event_process(node):
    #print("event process:", page_id)
    page_id = node.get_id()
    if page_id not in g_update_times:
        return 

    global ui_page_editors
    g_update_times[page_id] = g_update_times[page_id]-1
    if g_update_times[page_id] == 0:
        # 执行处理
        #print("................... update page.......")
        for editor in ui_page_editors:
            if editor._node.get_id() == page_id:
                #editor.emit(SIGNAL("update(node)"), node) 
                editor.update_node = node
                editor.windowTitleChanged.emit("node")
                #editor.on_init(node)

def on_select_item(event, node):
    global ui_page_editors
    for editor in ui_page_editors:
        editor.activate(node)

def on_modify_item(event, node, prop, value):
    global g_update_times

    if prop == 'Title' or prop == 'Text' or prop == 'WindowTitle':
        node.set_name(node.get_prop(prop))

    parent = node.parent()
    while True:
        print("parent:", parent)
        if parent == None:
            return 

        kind = parent.get_kind()
        print("parent kind:", kind)
        if kind == "Page":
            id = parent.get_id()
            if id in g_update_times:
                g_update_times[id] += 1
            else:
                g_update_times[id] = 1
            t = Timer(2, event_process, (parent,))
            t.start()
            return 
        
        if kind == "Project":
            return 

        parent = parent.parent()

def on_delete_item(event, node):
    global g_update_times

    parent = node.parent()
    while True:
        if parent == None:
            return 

        kind = parent.get_kind()
        if kind == "Page":
            id = parent.get_id()
            if id in g_update_times:
                g_update_times[id] += 1
            else:
                g_update_times[id] = 1

            t = Timer(2, event_process, (parent,))
            t.start()
            return 
        
        if kind == "Project":
            return 

        parent = parent.parent()

def on_add_item(event, parent_, child_):
    global g_update_times

    parent = parent_
    while True:
        if parent == None:
            return 

        kind = parent.get_kind()
        if kind == "Page":
            id = parent.get_id()
            if id in g_update_times:
                g_update_times[id] += 1
            else:
                g_update_times[id] = 1

            t = Timer(2, event_process, (parent,))
            t.start()
            return 
        
        if kind == "Project":
            return 

        parent = parent.parent()

def on_remove_item(event, parent_, child_, index):
    global g_update_times

    parent = parent_
    while True:
        if parent == None:
            return 

        kind = parent.get_kind()
        if kind == "Page":
            id = parent.get_id()
            if id in g_update_times:
                g_update_times[id] += 1
            else:
                g_update_times[id] = 1

            t = Timer(2, event_process, (parent,))
            t.start()
            return 
        
        if kind == "Project":
            return 

        parent = parent.parent()

class PropertyQAbstractButtonIcon:
    def name(self):
        return "QAbstractButton::Icon"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQLabelPixmap:
    def name(self):
        return "QLabel::Pixmap"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQLayoutContentsMargins:
    def name(self):
        return "QLayout::ContentsMargins"
    def type(self):
        return QVariant.String   #####
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQuickWidgetSource:
    def name(self):
        return "QQuickWidget::Source"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQSplitterOrientation:
    def name(self):
        return "QSplitter::Orientation"
    def type(self):
        return QVariant.String   #####
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQWebEngineViewUrl:
    def name(self):
        return "QWebEngineView::Url"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQWidgetStyleSheet:
    def name(self):
        return "QWidget::StyleSheet"
    def type(self):
        return QVariant.String #FileContent    #####
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQWidgetMaximumHeight:
    def name(self):
        return "QWidget::MaximumHeight"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQWidgetMaximumWidth:
    def name(self):
        return "QWidget::MaximumWidth"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQWidgetMinimumHeight:
    def name(self):
        return "QWidget::MinimumHeight"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQWidgetMinimumWidth:
    def name(self):
        return "QWidget::MinimumWidth"
    def type(self):
        return QVariant.String
    def edit(self, value):
        return value
    def display_value(self, value):
        return value

class PropertyQWidgetContentsMargins:
    def name(self):
        return "QWidget::ContentsMargins"
    def type(self):
        return QVariant.String   #####
    def edit(self, value):
        return value
    def display_value(self, value):
        return value



WidgetExtensionDef = '''
class WidgetExtension:
    def name(self):
        # 例如 'MyButton'
        pass
    def show_name(self):
        pass
    def parent_class(self):
        pass
    def properties(self):
        # 例如 {'ToolTip': { 'type': 'String',  'default': ''}}
        pass
    def create_child_methods(self):
        # 例如 {'default': 'setCentralWidget', 'QMenuBar': 'setMenuBar', 'QToolBar': 'addToolBar', 'QDockWidget': add_dock_widget }
        pass
    def create_widget(self,config):
        pass
    # 定义widget所属分组
    def group(self):
        # 例如 Button
        pass
'''

config = {
    'pluginid': 'UIPrototype::UI::Main',
    "extensions_def" : [
        {
            "name": "UIPrototype::Widget",
            "define": WidgetExtensionDef
        }
    ],
    "extensions" : [
        {
            "name": "PL::Basic::Editor",
            "id": "PL::Basic::Editor::UIRenderView",
            "impl": EditorExtension()
        },
        {
            "name": "PL::DataExplore::Menu",
            "id": "PL::Basic::Editor::UIPrototype::AddWidget",
            "impl": DataExploreMenu()
        },
        {
            "name": "PL::DataExplore::Menu",
            "id": "PL::Basic::Editor::UIPrototype::UpdateResource",
            "impl": DataExploreUpdateResourceMenu()
        },
         {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QAbstractButton::Icon",
            "impl": PropertyQAbstractButtonIcon()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QLabel::Pixmap",
            "impl": PropertyQLabelPixmap()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QLayout::ContentsMargins",
            "impl": PropertyQLayoutContentsMargins()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QQuickWidget::Source",
            "impl": PropertyQuickWidgetSource()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QSplitter::Orientation",
            "impl": PropertyQSplitterOrientation()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QWebEngineView::Url",
            "impl": PropertyQWebEngineViewUrl()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QWidget::StyleSheet",
            "impl": PropertyQWidgetStyleSheet()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QWidget::MaximumHeight",
            "impl": PropertyQWidgetMaximumHeight()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QWidget::MaximumWidth",
            "impl": PropertyQWidgetMaximumWidth()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QWidget::MinimumHeight",
            "impl": PropertyQWidgetMinimumHeight()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QWidget::MinimumWidth",
            "impl": PropertyQWidgetMinimumWidth()
        },
        {
            "name": "Core::Data::Property",
            "id": "UIPrototype::Data::Property::QWidget::ContentsMargins",
            "impl": PropertyQWidgetContentsMargins()
        }
    ],
    "subscribes" : [
        {
            "name": 'event::DataNode::Select',
            "define": on_select_item
        },
        {
            "name": 'event::DataNode::Modify::Prop',
            "define": on_modify_item
        },
        {
            "name": 'event::DataNode::Delete',
            "define": on_delete_item
        },
        {
            "name": 'event::DataNode::Modify::AddChild',
            "define": on_add_item
        },
        {
            "name": 'event::DataNode::Modify::RemoveChild',
            "define": on_remove_item
        }
    ]
}